
package JET;

import JET.Centers.ControlCenter;
import JET.geom.Vec2d;
import JET.physics.*;
import JET.physics.bodies.*;
import JET.physics.engine.JETContext;
import JET.physics.steering.Torque;

import XMLStuff.XMLConstants;
import XMLStuff.XMLHelper2;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author raos
 */
public class SceneCacheHelper {


    public static Element createCached(Scene s) throws ParserConfigurationException {
        Document doc = XMLHelper2.createNewDocument();
        return XMLHelper2.buildSceneElement(doc, s);
    }

    public static void loadCached(Scene s, Element sceneElem) throws TransformerConfigurationException, TransformerException, ParserConfigurationException, SAXException, IOException {
        Transformer t = TransformerFactory.newInstance().newTransformer();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        t.transform(new DOMSource(sceneElem), new StreamResult(baos));

        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
        saxParser.parse(new ByteArrayInputStream(baos.toByteArray()), new SceneCacheSAXHandler(s));
    }

    private static class SceneCacheSAXHandler extends DefaultHandler implements Constants, XMLConstants {

        private static final ControlCenter CC = ControlCenter.getInstance();
        private boolean debug = false;

        private enum RBLocation {
            BaseVertices,
            ExtraVertices
        }

        private Scene       curScene;       // currently parsed scene
        private SpringBody  curSB;          // currently parsed spring body
        
        private RigidBody   curRB;          // currently parsed rigid body
        private RBLocation  curRBLoc;       // current rigid body location

        private Mass        curMass;        // currently parsed mass
        private Spring      curSpring;      // currently parsed spring
        private RSpring     curRSpring;     // currently parsed rotary spring
        private Spring      curSMSpring;    // currently parsed shape matching spring
        private Wall        curWall;        // currently parsed wall
        private Vec2d       curBSV;         // currently parsed base shape vector
        private Torque      curTorque;      // currently parsed torque

        private ArrayList<Spring> sbSMSprings = new ArrayList<Spring>();    // helper to maintain shape matching spring body springs while they are loaded...

        public SceneCacheSAXHandler(Scene s) {
            curScene = s;
        }

        @Override
        public void startDocument() throws SAXException {}
        @Override
        public void endDocument() throws SAXException {}

        @Override
        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
            if (debug) System.out.println("element start: "+qName);

            if (ELEMENT_NAME_SCENE.equals(qName)) {
                curScene.setJETContext(new JETContext());
            } else if (ELEMENT_NAME_SIMULATION.equals(qName)) {
                if (curScene!=null) XMLHelper2.buildSimulation(atts, curScene);
            } else if (ELEMENT_NAME_SPRINGBODY.equals(qName)) {
                curSB = XMLHelper2.buildSpringBody(atts);
            } else if (ELEMENT_NAME_RIGIDBODY.equals(qName)) {
                curRB = XMLHelper2.buildRigidBody(atts);
            } else if (ELEMENT_NAME_MASS.equals(qName)) {
                curMass = XMLHelper2.buildMass(atts);
            } else if (ELEMENT_NAME_POSITION.equals(qName)) {
                if (curMass != null) {
                    curMass.setPosition(XMLHelper2.buildVec2d(atts));
                }
            } else if (ELEMENT_NAME_VELOCITY.equals(qName)) {
                if (curMass!=null) {
                    curMass.setVelocity(XMLHelper2.buildVec2d(atts));
                }
            } else if (ELEMENT_NAME_FORCE.equals(qName)) {
                if (curMass!=null) {
                    curMass.setForce(XMLHelper2.buildVec2d(atts));
                }
            } else if (ELEMENT_NAME_SPRING.equals(qName)) {
                curSpring = XMLHelper2.buildSpring(atts, curScene.getJETContext(), curSB, curRB);
            } else if (ELEMENT_NAME_RSPRING.equals(qName)) {
                curRSpring = XMLHelper2.buildRSpring(atts, curScene.getJETContext(), curSB);
            } else if (ELEMENT_NAME_WALL.equals(qName)) {
                if (curSB!=null) {
                    curWall = XMLHelper2.buildWall(atts, curSB);
                } else if (curRB!=null) {
                    curWall = XMLHelper2.buildWall(atts, curRB);
                }
            } else if (ELEMENT_NAME_SMSPRING.equals(qName)) {
                curSMSpring = XMLHelper2.buildSMSpring(atts, curSB);
            } else if (ELEMENT_NAME_SMSPRINGS.equals(qName)) {
                if (curSB!=null) {
                    curSB.smSprings = new Spring[Integer.parseInt(atts.getValue("count"))];
                    sbSMSprings.clear();
                }
            } else if (ELEMENT_NAME_BASESHAPEVECTOR.equals(qName)) {
                curBSV = XMLHelper2.buildVec2d(atts);
            } else if (ELEMENT_NAME_MATERIALPAIR.equals(qName)) {
                if (curScene!=null) {
                    XMLHelper2.buildMaterialPair(atts, curScene);
                }
            } else if (ELEMENT_NAME_TORQUE.equals(qName)) {
                if (curScene!=null) {
                    curTorque = XMLHelper2.buildTorque(atts, curScene);
                }
            } else if (ELEMENT_NAME_MASSLIST.equals(qName)) {
                if (curTorque!=null) {
                    curTorque.getMassList().addAll(XMLHelper2.buildMasslist(atts, curScene));
                }
            } else if ("rbvertices".equals(qName)) {
                curRBLoc = RBLocation.BaseVertices;
            } else if ("rbextravertices".equals(qName)) {
                curRBLoc = RBLocation.ExtraVertices;
            } else if ("rbvertex".equals(qName)) {
                if (curRB!=null) {
                    Mass m = new Mass(1,1,1);
                    Vec2d v = new Vec2d();
                    XMLHelper2.buildRigidBodyVertex(atts, v, m);
                    switch(curRBLoc) {
                        case BaseVertices:
                            curRB.baseVecList.add(v);
                            curRB.dynVecList.add(m);
                            break;
                        case ExtraVertices:
                            curRB.extraBaseVecList.add(v);
                            curRB.extraDynMassList.add(m);
                            break;
                    }
                }
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (debug) System.out.println("element end: "+qName);

            if (ELEMENT_NAME_SCENE.equals(qName)) {
                curScene = null;
            } else if (ELEMENT_NAME_SPRINGBODY.equals(qName)) {
                if (curScene!=null) curScene.getJETContext().addSpringBody(curSB);
                curSB = null;
            } else if (ELEMENT_NAME_RIGIDBODY.equals(qName)) {
                if (curSB!=null) curSB.rb = curRB;
                else if (curScene!=null) curScene.getJETContext().addRigidBody(curRB);
                curRB = null;
            } else if (ELEMENT_NAME_MASS.equals(qName)) {
                if (curSB!=null) {
//                    if (curRB!=null) {// adding mass to rigid body of spring body
//                        curRB.dynVecList.add(curMass);
//                    } else {
                       curSB.addMass(curMass); // adding mass to spring body of a scene
//                    }
                } else if (curRB!=null) {
                    curRB.dynVecList.add(curMass); // adding mass to rigid body of a scene
                }
                curMass = null;
            } else if (ELEMENT_NAME_SPRING.equals(qName)) {
                if (curSB!=null)    curSB.addSpring(curSpring);
                else                curScene.getJETContext().addSpring(curSpring);
                curSpring = null;
            } else if (ELEMENT_NAME_RSPRING.equals(qName)) {
                if (curSB!=null)    curSB.addRSpring(curRSpring);
                else                curScene.getJETContext().addRSpring(curRSpring);
                curRSpring = null;
            } else if (ELEMENT_NAME_WALL.equals(qName)) {
                if (curSB!=null) curSB.addWallToBorder(curWall);
                else if (curRB!=null) curRB.border.addWall(curWall);
                curWall = null;
            } else if (ELEMENT_NAME_SMSPRING.equals(qName)) {
                if (curSB!=null) {
                    sbSMSprings.add(curSMSpring);
                }
            } else if (ELEMENT_NAME_SMSPRINGS.equals(qName)) {
                if (curSB!=null) {
                    for(int i=0; i<sbSMSprings.size(); i++)
                        curSB.smSprings[i] = sbSMSprings.get(i);
                }
            } else if (ELEMENT_NAME_BASESHAPEVECTOR.equals(qName)) {
                if (curRB!=null) curRB.baseVecList.add(curBSV);
                curBSV = null;
            } else if (ELEMENT_NAME_MATERIALPAIR.equals(qName)) {
                // Do nothing
            } else if (ELEMENT_NAME_TORQUE.equals(qName)) {
                if (curScene!=null) curScene.getJETContext().addTorque(curTorque);
                curTorque = null;
            } else if (ELEMENT_NAME_MASSLIST.equals(qName)) {
                // Do nothing
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {}

       
    }

}
